#include "raw_connection.h"
#include "../Errors/errors.h"
#include "../packet_headers/iphdr.h"
#include "../packet_headers/etherhdr.h"
#include "info.h"
/*#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/ip.h>
#include <netinet/udp.h>
#include <errno.h>*/
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <linux/if_ether.h>
#include <netpacket/packet.h>
#include <net/ethernet.h>
#include <netinet/ether.h>

#define ETHERTYPE_LEN 2
#define MAC_ADDR_LEN 6

/* Initialize a raw connection; specifies ip, port and protocol for
   both the host and for self; IP spoofing is allowed in this case.

   For client: src is own address, dest is address to send packets to.
   For server: src is address of sender, dest is own address. 			*/
RawConnection::RawConnection(const char * _dev) {
	pdhdw = new char[sizeof(struct sockaddr_ll)];
	struct sockaddr_ll * dhdw = (struct sockaddr_ll*) pdhdw;
	lochw = get_local_mac(_dev);
	gtwhw = get_gateway_mac(_dev);
	short int etherTypeT = htons(0x8200);
	memset(dhdw, 0, sizeof(struct sockaddr_ll));
	dhdw->sll_family = htons(PF_PACKET);
	dhdw->sll_protocol = htons(ETH_P_ALL);
	dhdw->sll_halen = 6;
	dhdw->sll_ifindex = 2;
	dhdw->sll_pkttype = PACKET_OTHERHOST;
	memcpy(&(dhdw->sll_addr), gtwhw, MAC_ADDR_LEN);
	dhdw->sll_addr[6] = 0;
	dhdw->sll_addr[7] = 0;

	// Open raw socket
	sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
	if(sock < 0)
	{
		state = errno;
		auto_set_error_message(errno);
		//set_error_message("Failed to initialize socket.");
		return;
	}
	sockfd = sock;
	state = 0;
}

int RawConnection::send(const char * _buf, unsigned int _len) {
	struct ipheader * iphdr = (struct ipheader*) (_buf+sizeof(struct etherheader));
	struct sockaddr_ll * dhdw = (struct sockaddr_ll*) pdhdw;
	int result = sendto(sock, _buf,
			_len+sizeof(struct etherheader), 0,
			(struct sockaddr *)dhdw, sizeof(*dhdw));
	if(result < 0) {
		state = errno;
		auto_set_error_message(errno);
		return -1;
	}
	return result;
}

int RawConnection::finish() {
	close(sock);
	return 0;
}
